﻿#pragma once

#include "kernel/kernel.h"

namespace CAGD
{

/**
 * 四元数类型.
 */
class Quaternion
{
  protected:
    double m_s;
    BVec m_v;

  public:
    /**
     * @brief 基本构造.
     * @param s
     * @param v
     * @see
     */
    Quaternion(double s = 0, BVec v = {0, 0, 0});

    /**
     * @brief 获得 p 绕轴 v 逆时针旋转 theta 角的四元数 q, (q * p / q).
     * @param v
     * @param theta
     * @see
     */
    Quaternion(BVec v, double theta);

    /**
     * @brief 获得从轴 a 转动到轴 b 的四元数，只保证方向相同，不保证转动后长度相同.
     * @param a
     * @param b
     * @see
     */
    Quaternion(BVec a, BVec b);

    /**
     * @brief 基本乘法.
     * @return
     * @param t
     * @see
     */
    Quaternion operator*(double t) const;

    /**
     * @brief 基本除法.
     * @return
     * @param t
     * @see
     */
    Quaternion operator/(double t) const;

    /**
     * @brief 加法运算.
     * @return
     * @param q
     * @see
     */
    Quaternion operator+(const Quaternion &q) const;

    /**
     * @brief 减法运算.
     * @return
     * @param q
     * @see
     */
    Quaternion operator-(const Quaternion &q) const;

    /**
     * @brief 乘法运算.
     * @return
     * @param q
     * @see
     */
    Quaternion operator*(const Quaternion &q) const;

    /**
     * @brief 除法运算.
     * @return
     * @param q
     * @see
     */
    Quaternion operator/(const Quaternion &q) const;

    /**
     * @brief 比较运算.
     * @return
     * @param q
     * @see
     */
    bool operator==(const Quaternion &q) const;

    /**
     * @brief 四元数规范化.
     * @see
     */
    void Normalize();

    /**
     * @brief 四元数规范化.
     * @return
     * @see
     */
    Quaternion Normalized() const;

    /**
     * @brief 取模.
     * @return
     * @see
     */
    double Modulus() const;

    /**
     * @brief 取模.
     * @return
     * @see
     */
    double SquareModulus() const;

    /**
     * @brief 取实数部分.
     * @return
     * @see
     */
    double S() const;

    /**
     * @brief 设置实数部分.
     * @param s
     * @see
     */
    void SetS(double s);

    /**
     * @brief 取向量部分.
     * @return
     * @see
     */
    BVec V() const;

    /**
     * @brief 设置向量部分.
     * @param v
     * @see
     */
    void SetV(const BVec &v);

    /**
     * @brief 输出函数.
     * @return
     * @param os
     * @param q
     * @see
     */
    friend std::ostream &operator<<(std::ostream &os, const Quaternion &q)
    {
        os << "{" << q.S() << " + " << q.V().X() << "i + " << q.V().Y() << "j + " << q.V().Z() << "k}" << std::endl;
        return os;
    }
};

} // namespace CAGD
